#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import codecs

import wx
import wx.stc

from misc import config
import tex

class TexEditor (wx.stc.StyledTextCtrl):
	"""Поле ввода с подсветкой команд"""
	def __init__ (self, parent, id = wx.ID_ANY, \
			pos = wx.DefaultPosition, \
			size = wx.DefaultSize,\
			style = 0,\
			name = "editor"):
		wx.stc.StyledTextCtrl.__init__ (self, parent, id, pos, size, style, name)
		
		self.SetLexer (wx.stc.STC_LEX_CONTAINER)
		self.encoder = codecs.getencoder("utf-8")

		self.autoCompItems = []
		
		# Стили
		self.default_style = 0
		self.subscript_style = 1
		self.superscript_style = 2
		self.command_style = 3
		self.greek_style = 4
		self.subcommand_style = 5
		self.supercommand_style = 6
		
		self.intelliSenseFile = "intelli.txt"
		self.autoCompItems = []
		
		try:
			self.autoCompItems = [item.strip() for item in file(self.intelliSenseFile).readlines()]
			self.autoCompItems.sort()
		except IOError:
			wx.MessageBox (u"Невозможно открыть файл с подсказками intelli.txt", u"Ошибка", wx.OK | wx.ICON_ERROR)
		
		# Список для автозавершения
		#self.autoCompItems = []
		
		# Настройки стилей
		self.loadStyles()

		self.Bind (wx.stc.EVT_STC_CHARADDED, self.onCharAdded)
		self.Bind (wx.stc.EVT_STC_UPDATEUI, self.onCheckBrace)
		self.Bind (wx.stc.EVT_STC_STYLENEEDED, self.onStyleNeeded)


	def loadStyles (self):
		self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, config.instance().default_style)
		self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT, config.instance().bracelight_style)
		self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD, config.instance().bracebad_style)
		
		self.StyleSetSpec(self.subscript_style,  config.instance().subscript_style)
		self.StyleSetSpec(self.superscript_style,  config.instance().superscript_style)
		

		self.StyleSetSpec(self.command_style,  config.instance().command_style)
	
	def calcByteLen(self, text):
		"""Посчитать длину строки в байтах, а не в символах"""
		return len(self.encoder(text)[0])
	
	def calcBytePos (self, text, pos):
		"""Преобразовать позицию в символах в позицию в байтах"""
		return len(self.encoder (text[: pos] )[0] )
	
	def colorizeCommands (self, text, lexers):
		"""Раскрасить команды"""
		for lexer in lexers:
			if type(lexer) is tex.CommandLexer:
				# Позиция в байтах
				bytepos = self.calcBytePos (text, lexer.position)
				#print "pos: %d" % bytepos
				
				# Находим длину искомой строки в байтах
				text_byte_len = self.calcByteLen (lexer.text)
				#print "len: %d" % text_byte_len
				
				self.StartStyling (bytepos, 0x1f)
				self.SetStyling (text_byte_len, self.command_style)
	
	def colorizeLexer (self, text, lexer, style, mask = 0xff):
		bytepos = self.calcBytePos (text, lexer.position)
		
		# Находим длину искомой строки в байтах
		text_byte_len = self.calcByteLen (lexer.text)
		
		self.StartStyling (bytepos, mask)
		#self.GetEndStyled()
		self.SetStyling (text_byte_len, style)
	
	
	def colorizeSubSuperscript (self, text, lexers, lexertype, style):
		# Начали раскрашивать
		colorize = False
		
		# Во сколько групп {} мы вошли
		group = 0
		
		for lexer in lexers:
			if type (lexer) is lexertype:
				# Нашли команду для нижнего индекса
				colorize = True
				#self.colorizeLexer (text, lexer, style, mask = wx.stc.STC_INDICS_MASK)
				self.colorizeLexer (text, lexer, style)
				continue
			elif colorize:
				# Уже начали раскрашивать
				#self.colorizeLexer (text, lexer, style, mask = wx.stc.STC_INDICS_MASK)
				self.colorizeLexer (text, lexer, style)
			
			if colorize and type (lexer) is tex.BeginGroupLexer:
				group += 1
				#self.colorizeLexer (text, lexer, style, mask = wx.stc.STC_INDICS_MASK)
				self.colorizeLexer (text, lexer, style)
				continue
			
			if colorize and type (lexer) is tex.EndGroupLexer:
				group -= 1
				#self.colorizeLexer (text, lexer, style, mask = wx.stc.STC_INDICS_MASK)
				self.colorizeLexer (text, lexer, style)
				
				if group == 0:
					colorize = False
				continue
				
			if group == 0:
				colorize = False
			
	
	def onStyleNeeded (self, event):
		text = self.GetText()
		parser = tex.TexParser()
		lexers = parser.parse(text)
		
		self.StartStyling (0, 0xff)
		self.SetStyling (self.calcByteLen (text), self.default_style)
		
		self.colorizeCommands (text, lexers)
		
		self.colorizeSubSuperscript (text, lexers, tex.SubscriptLexer, self.subscript_style)
		self.colorizeSubSuperscript (text, lexers, tex.SuperscriptLexer, self.superscript_style)
	
	def onCheckBrace (self, event):
		# Получим текущую позицию в байтах
		pos = self.GetCurrentPos() 
		
		text = self.GetText()
		text_len = self.calcByteLen (text)
		
		text_left = u""
		if pos> 0:
			text_left = self.GetTextRange (pos - 1, pos)
			#print text_left
			
		text_right = u""
		if pos < text_len:
			text_right = self.GetTextRange (pos, text_len)
		
		#print "pos: " + str(pos)
		
		# Проверим есть ли слева скобка
		if len(text_left) > 0 and text_left[-1] in "{}()[]":
			match = self.BraceMatch(pos - 1)
			#print "match: " + str(match)
			
			# нашли парную скобку
			if match != wx.stc.STC_INVALID_POSITION:
				# Подсветим обе
				self.BraceHighlight(pos - 1, match)
				return
			else:
				# Иначе подсветим первую скобку как ошибочную
				self.BraceBadLight(pos - 1)
				return
		else:
			# В этой позиции не скобка, отключим подсветку
			self.BraceBadLight(wx.stc.STC_INVALID_POSITION)
			
		# Если не нашли скобку слева, проверим есть ли она справа
		if len(text_right) > 0 and text_right[0] in "{}()[]":
			match = self.BraceMatch(pos)
			#print "match: " + str(match)
			
			# нашли парную скобку
			if match != wx.stc.STC_INVALID_POSITION:
				# Подсветим обе
				self.BraceHighlight(pos, match)
				return
			else:
				# Иначе подсветим первую скобку как ошибочную
				self.BraceBadLight(pos)
				return
		else:
			# В этой позиции не скобка, отключим подсветку
			self.BraceBadLight(wx.stc.STC_INVALID_POSITION)

	def showAutoComp (self):
		pos = self.GetCurrentPos()
		text = self.GetText()[: pos]
		
		# Найдем, где начинается команда
		startpos = text.rfind ("\\")
		if startpos != -1:
			substr = text[startpos: pos]
			#print substr
			intelli_items = [item for item in self.autoCompItems if item.startswith (substr) ]
			
			if len (intelli_items) != 0:
				items_text = reduce (lambda x, y: x + " " + y, intelli_items)
				#self.AutoCompSetFillUps ("")
				#self.AutoCompSetDropRestOfWord (1)
				#self.AutoCompSetChooseSingle (True)
				self.AutoCompShow (len (substr) ,items_text)

	def onCharAdded (self, event):
		key_raw = event.GetKey()

		if key_raw < 256:
			key = chr (key_raw)
			
			open = "{(["
			close = "})]"
			
			right_text = "\\right"
			left_text = "\\left"
			
			keyindex = open.find (key)
			
			if keyindex != -1:
				pos = self.GetCurrentPos()
				text = self.GetText()
				
				#print text[:pos]
				if text[:pos - 1].endswith (left_text):
					self.AddText(right_text + close[keyindex] )
					self.GotoPos (pos)
				else:
					self.AddText(close[keyindex] )
					self.GotoPos (pos)

			self.showAutoComp()
